Skip to content

Scan Management API ​

This document is based on the following source files:

  • internal/handlers/scan.go -- Scan handler (scan actions + business settings endpoints)
  • internal/app/routers.go -- Route registration
  • internal/services/scan_progress.go -- Scan progress model
  • internal/services/fingerprint.go -- Fingerprint computation service

Table of Contents ​

  1. Overview
  2. Scan Operation Endpoints
  3. Fingerprint Computation Endpoints
  4. Scan Business Settings Endpoints

1. Overview ​

The scan management module handles the discovery, importing, and directory management of local music files. All endpoints require JWT authentication (BearerAuth), with the base path /api/v1.

ScanHandler carries both the scan action endpoints and the scan-related business settings endpoints (/settings/*), consolidating the business-oriented reads/writes of config keys such as music_path and scan_playlist_mode into a single handler.


2. Scan Operation Endpoints ​

2.1 POST /scan -- Scan and Import Local Music ​

Method: POSTPath: /api/v1/scanAuthentication: BearerAuth required

Description: Asynchronously scans the music directory and imports newly discovered music files into the database. Returns immediately; status can be polled via /scan/progress.

Request body:

json
{
  "reimport": false
}
FieldTypeRequiredDescription
reimportbooleanNoWhether to re-import files that already exist (default false)

Success response (200):

json
{
  "message": "扫描任务已启动"
}

Error responses:

StatusDescription
409A scan is already in progress
500Failed to start scan

2.2 GET /scan/progress -- Get Scan Progress ​

Method: GETPath: /api/v1/scan/progressAuthentication: BearerAuth required

Description: Gets progress information for the current scan task.

Success response (200):

json
{
  "status": "scanning",
  "total_files": 1000,
  "scanned_files": 500,
  "imported_files": 480,
  "skipped_files": 15,
  "failed_files": 5,
  "cleaned_files": 0,
  "current_file": "/music/album/track.mp3",
  "start_time": "2026-06-12T10:00:00Z",
  "end_time": null,
  "error": ""
}
FieldTypeDescription
statusstringCurrent status: idle / scanning / importing / creating_playlists / completed / failed / cancelling / cancelled
total_filesintTotal number of files
scanned_filesintNumber of scanned files
imported_filesintNumber of imported files
skipped_filesintNumber of skipped files (already exist)
failed_filesintNumber of failed files
cleaned_filesintNumber of stale files cleaned up
current_filestringPath of the file currently being processed
start_timestring/nullStart time (ISO 8601)
end_timestring/nullEnd time (ISO 8601)
errorstringError message

2.3 POST /scan/cancel -- Cancel Scan ​

Method: POSTPath: /api/v1/scan/cancelAuthentication: BearerAuth required

Description: Cancels the scan task in progress.

Success response (200):

json
{
  "message": "扫描任务已取消"
}

Error responses:

StatusDescription
400No scan task is in progress

2.4 GET /scan/directories -- Get Subdirectory List ​

Method: GETPath: /api/v1/scan/directoriesAuthentication: BearerAuth required

Description: Returns the list of first-level subdirectories under the specified path, used for lazy loading of the directory tree. When path is empty, returns the subdirectories under the music root directory.

Query parameters:

ParameterTypeRequiredDescription
pathstringNoDirectory path (uses the music root directory when empty)

Success response (200):

json
{
  "directories": ["/music/pop", "/music/rock"],
  "root": "/music"
}

Error responses:

StatusDescription
400The path must be under the music directory (prevents directory traversal attacks)
500Failed to read directory

2.5 GET /scan/dir-names -- Get All Directory Names ​

Method: GETPath: /api/v1/scan/dir-namesAuthentication: BearerAuth required

Description: Recursively collects all unique directory names under the music directory, returned in alphabetical order, used for autocompletion of excluded directory names.

Success response (200):

json
{
  "names": ["@eaDir", "Classical", "Pop", "Rock", "tmp"]
}

Error responses:

StatusDescription
500Failed to collect directory names

3. Fingerprint Computation Endpoints ​

3.1 GET /scan/fingerprints/status -- Get Fingerprint Computation Status ​

Method: GETPath: /api/v1/scan/fingerprints/statusAuthentication: BearerAuth required

Description: Returns ffmpeg chromaprint availability and local song fingerprint computation statistics.

Success response (200):

json
{
  "chromaprint_available": true,
  "total": 1000,
  "computed": 795,
  "missing": 200,
  "failed": 5,
  "auto_enabled": false
}
FieldTypeDescription
chromaprint_availablebooleanWhether ffmpeg chromaprint is available
totalintTotal number of local songs
computedintNumber of songs with computed fingerprints
missingintNumber of songs never attempted yet (= total - computed - failed)
failedintNumber of songs attempted but failed (no audio track / corrupted / timed out). Never retried automatically — only recompute_all=true tries again
auto_enabledbooleanWhether fingerprints are computed automatically after a scan (config scan_auto_fingerprint, default false)

3.2 POST /scan/fingerprints -- Trigger Batch Fingerprint Computation ​

Method: POSTPath: /api/v1/scan/fingerprintsAuthentication: BearerAuth required

Description: Asynchronously computes audio fingerprints for local songs; requires ffmpeg with chromaprint support. If a task is already running, it is interrupted and restarted. Each file samples only its first 120 seconds (the AcoustID standard), concurrency adapts to the CPU (clamp(GOMAXPROCS/4, 1, 4)), and failed songs are marked as "attempted" so they are not retried automatically.

Request body:

json
{
  "recompute_all": false
}
FieldTypeRequiredDescription
recompute_allbooleanNoWhen true, clears existing fingerprints and the "attempted" markers, then recomputes everything (default false, computes only songs never attempted). This is the only way to retry failed items

Success response (200):

json
{
  "status": "started",
  "total": 200
}

Error responses:

StatusDescription
400ffmpeg chromaprint is unavailable

3.3 GET /scan/fingerprints/progress -- Get Fingerprint Computation Progress ​

Method: GETPath: /api/v1/scan/fingerprints/progressAuthentication: BearerAuth required

Description: Queries the progress of the current fingerprint computation task.

Success response (200):

json
{
  "status": "running",
  "computed": 150,
  "total": 200,
  "failed": 3
}
FieldTypeDescription
statusstringTask status: idle / running / done / cancelled
computedintNumber computed
totalintTotal number of tasks
failedintNumber failed

3.4 POST /scan/fingerprints/cancel -- Interrupt Fingerprint Computation ​

Method: POSTPath: /api/v1/scan/fingerprints/cancelAuthentication: BearerAuth required

Description: Stops the running batch fingerprint computation task and kills its ffmpeg child processes. The fingerprint task is not attached to the scan's cancel channel (that channel is already closed once the scan reports "completed"), so it needs a dedicated cancel entry point. Fingerprints already computed are kept; interrupted songs are not marked as "attempted" and will be computed next time.

Success response (200):

json
{
  "cancelled": true
}
FieldTypeDescription
cancelledbooleanWhether a running task was actually interrupted (false when none is running; not an error)

4. Scan Business Settings Endpoints ​

The following endpoints are business-oriented configuration interfaces that provide strongly-typed JSON, come with built-in defaults, and trigger side effects inline after PUT. They write to the same config row as the generic /configs/{key} interface, but frontend business features should always go through these endpoints.

4.1 GET/PUT /settings/music-path -- Music Path Configuration ​

Path: /api/v1/settings/music-pathAuthentication: BearerAuth required

GET -- Get music path and scan exclusion configuration ​

Success response (200):

json
{
  "path": "music",
  "exclude_dirs": ["@eaDir", "tmp"],
  "exclude_paths": []
}
FieldTypeDescription
pathstringMusic directory path (default "music")
exclude_dirsstring[]List of excluded directory names
exclude_pathsstring[]List of excluded specific paths

PUT -- Update music path and scan exclusion configuration ​

After writing the configuration, asynchronously triggers a Scanner rebuild + cleanup of songs in excluded directories (the side effect is consistent with the admin /configs/music_path PUT).

Request body: Same format as the GET response. path cannot be empty.

Error responses:

StatusDescription
400Bad request format or empty path
500Failed to save configuration

4.2 GET/PUT /settings/scan-playlist-mode -- Playlist Merge Mode ​

Path: /api/v1/settings/scan-playlist-modeAuthentication: BearerAuth required

Controls the directory merge mode when automatically creating playlists after a scan. Default directory.

GET response / PUT request body: ​

json
{
  "mode": "directory"
}
FieldTypeAllowed valuesDescription
modestringdirectory / top_level / bubble_updirectory: generate an independent playlist for each folder (default); top_level: merge playlists by first-level subdirectory; bubble_up: songs appear simultaneously in the playlists of all parent folders

PUT error responses:

StatusDescription
400Bad request format or illegal mode value (only the three enum values above are accepted)
500Failed to save configuration

4.3 GET/PUT /settings/scan-auto-create-playlists -- Auto-Create Playlists Switch ​

Path: /api/v1/settings/scan-auto-create-playlistsAuthentication: BearerAuth required

Controls whether playlists are automatically created based on the music directory structure after a scan completes. Enabled by default (true). When disabled, scanning only imports songs into the database and no longer auto-creates playlists.

GET response / PUT request body: ​

json
{
  "enabled": true
}

4.4 GET/PUT /settings/scan-auto-fingerprint -- Auto Audio-Fingerprint Switch ​

Path: /api/v1/settings/scan-auto-fingerprintAuthentication: BearerAuth required

Controls whether chromaprint audio fingerprints are computed automatically for local songs that lack them after a scan completes. Off by default (false): fingerprints only serve "Duplicate detection" and plugin lyric/cover search, making them an on-demand feature, and computing them library-wide keeps the CPU busy long after the scan progress already reads "completed" (songloft-org/songloft#323). While off, users can trigger POST /scan/fingerprints manually from the duplicate detection page.

Once enabled, per-file cost is constant (only the first 120 seconds are sampled), concurrency adapts to the CPU, failures are attempted only once, and the task can be stopped at any time via POST /scan/fingerprints/cancel.

GET response / PUT request body: ​

json
{
  "enabled": false
}

4.5 GET/PUT /settings/scan-title-source -- Scan Title Source Configuration ​

Path: /api/v1/settings/scan-title-sourceAuthentication: BearerAuth required

Configures the source of the song title during scanning. After switching, a scan in "re-import" mode is required for it to take effect. Triggers a Scanner rebuild after PUT completes.

GET response / PUT request body: ​

json
{
  "title_source": "tag"
}
FieldTypeAllowed valuesDescription
title_sourcestringtag / filenametag: prefer the title in the audio tags (default); filename: always use the file name (without extension)

PUT error responses:

StatusDescription
400Bad request format or invalid title_source value
500Failed to save configuration

4.6 GET/PUT /settings/auto-scan -- Auto Scan Configuration ​

Path: /api/v1/settings/auto-scanAuthentication: BearerAuth required

Configures the enabled state and scan interval of auto scan. Takes effect immediately after an update (no restart required), asynchronously triggering the auto-scan scheduler to reconfigure.

GET response / PUT request body: ​

json
{
  "enabled": false,
  "interval_seconds": 3600
}
FieldTypeDescription
enabledbooleanWhether to enable auto scan (default false)
interval_secondsintScan interval in seconds (default 3600, valid range 60-86400)

PUT error responses:

StatusDescription
400Bad request format or interval_seconds not in the range 60-86400
500Failed to save configuration

Section source: internal/handlers/scan.go / internal/app/routers.go / internal/services/scan_progress.go / internal/services/fingerprint.go